import type {
  AxiosInstance,
  AxiosError,
  AxiosRequestConfig,
  AxiosResponse,
} from "axios";
import axios from "axios";
import { ElMessage } from "element-plus";
import type { Tarot } from "@/utils/result";

enum RequestEnums {
  TIMEOUT = 20000, // 超时时间
  OVERDUE = 500, // 登录失效
  ERROR = 500, // 请求失败
  SUCCESS = 200, // 请求成功
}
const config = {
  // 默认地址
  baseURL: "/api",
  // 设置超时时间
  timeout: RequestEnums.TIMEOUT as number,
  // 跨域时候允许携带凭证
  withCredentials: true,
};

class RequestHttp {
  // 定义成员变量并指定类型
  service: AxiosInstance;
  public constructor(config: AxiosRequestConfig) {
    // 实例化axios
    this.service = axios.create(config);

    this.service.interceptors.request.use(
      /**
       * 请求拦截器
       * 客户端发送请求 -> [请求拦截器] -> 服务器
       * token校验(JWT) : 接受服务器返回的token,存储到vuex/pinia/本地储存当中
       */
      // @ts-ignore
      (config: AxiosRequestConfig) => {
        const token = localStorage.getItem("token") || "";
        return {
          ...config,
          headers: {
            "x-access-token": token, // 请求头中携带token信息
          },
        };
      },
      // 请求报错
      (error: AxiosError) => {
        Promise.reject(error);
      },
    );

    /**
     * 响应拦截器
     * 服务器换返回信息 -> [拦截统一处理] -> 客户端JS获取到信息
     */
    this.service.interceptors.response.use(
      (response: AxiosResponse) => {
        const { data, config } = response; // 解构

        console.log("返回数据===", data, config);

        if (data.code === RequestEnums.OVERDUE) {
          // 登录信息失效，应跳转到登录页面，并清空本地的token
          localStorage.setItem("token", "");
          // router.replace({
          //  path: "/login"
          // })
          return Promise.reject(data);
        }
        // 全局错误信息拦截（防止下载文件得时候返回数据流，没有code，直接报错）
        if (data.code && data.code !== RequestEnums.SUCCESS) {
          ElMessage.error(data.msg);
          return Promise.reject(data);
        }
        return data;
      },
      (error: AxiosError) => {
        const { response } = error;
        if (response) {
          this.handleCode(response.data);
        }
        if (!window.navigator.onLine) {
          ElMessage.error("网络连接失败，请检查网络");
          // 可以跳转到错误页面，也可以不做操作
          // return router.replace({
          //  path: "/404"
          // });
        }
      },
    );
  }
  handleCode(error: any): void {
    const { code, msg } = error;
    ElMessage.error(code + ": " + msg);
  }

  // 常用方法封装
  get<T>(url: string, params?: object): Promise<Tarot.ResultResponse<T>> {
    return this.service.get(url, { params });
  }
  post<T>(url: string, params?: object): Promise<Tarot.ResultResponse<T>> {
    return this.service.post(url, params);
  }
  put<T>(url: string, params?: object): Promise<Tarot.ResultResponse<T>> {
    return this.service.put(url, params);
  }
  delete<T>(url: string, params?: object): Promise<Tarot.ResultResponse<T>> {
    return this.service.delete(url, { params });
  }
  // @ts-ignore
  upload<T>(
    url: string,
    element: any,
    params?: any,
  ): Promise<Tarot.ResultResponse<T>> {
    const file = element.target.files[0];
    const param = new FormData();
    param.append("file", file);
    for (const key in params) {
      param.append(key, params[key]);
    }
    const config = {
      headers: { "Content-Type": "multipart/form-data" }, //请求头
      timeout: { timeout: 300000 },
    };
    // @ts-ignore
    return this.service.post(url, param, config);
  }
}

// 导出一个实例对象
export default new RequestHttp(config);
